home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Libraries / stdwin / Ports / mac / event.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-04-06  |  13.6 KB  |  738 lines  |  [TEXT/????]

  1. /* MAC STDWIN -- EVENT HANDLING. */
  2.  
  3. #include "macwin.h"
  4. #ifdef MPW
  5. #include <Events.h>
  6. #include <Menus.h>
  7. #include <Desk.h>
  8. #include <ToolUtils.h>
  9. #endif
  10. #ifdef THINK_C_PRE_5_0
  11. #include <EventMgr.h>
  12. #endif
  13. #ifdef THINK_C
  14. #ifndef THINK_C_3_0
  15. #include <console.h> /* See do_update */
  16. #endif
  17. #endif
  18.  
  19. void (*_w_idle_proc)();    /* Function to call in idle loop */
  20.  
  21. WINDOW *active= NULL;    /* The active window */
  22.             /* XXX should be a less obvious name */
  23. bool _wm_down;        /* Set if mouse is down in content rect */
  24.  
  25. static EventRecord e;    /* Global, so it's accessible to all subroutines */
  26.             /* XXX the name is too short */
  27.  
  28. /* Function prototypes */
  29.  
  30. STATIC void make_mouse_event _ARGS((EVENT *ep, Point *pwhere));
  31. STATIC void do_idle _ARGS((EVENT *ep));
  32. STATIC void do_update _ARGS((EVENT *ep));
  33. STATIC void do_mouse_down _ARGS((EVENT *ep));
  34. STATIC void do_mouse_up _ARGS((EVENT *ep));
  35. STATIC void do_key _ARGS((EVENT *ep));
  36. STATIC void do_activate _ARGS((EVENT *ep));
  37. STATIC void do_disk _ARGS((EVENT *ep));
  38. STATIC void activate _ARGS((WINDOW *win));
  39. STATIC void deactivate _ARGS((void));
  40.  
  41. STATIC void do_click _ARGS((EVENT *ep, WindowPtr w));
  42. STATIC void do_unclick _ARGS((EVENT *ep));
  43. STATIC void do_drag _ARGS((WindowPtr w));
  44. STATIC void do_grow _ARGS((EVENT *ep, WindowPtr w));
  45. STATIC void do_goaway _ARGS((EVENT *ep, WindowPtr w));
  46. STATIC void do_zoom _ARGS((EVENT *ep, WindowPtr w, int code));
  47. STATIC void do_size _ARGS((EVENT *ep, WindowPtr w));
  48.  
  49. # ifndef NO_STDIO
  50. /* Some applications (e.g., Python) want events passed to the stdio console.
  51.    They must call wsetstdio(1) before their first wgetevent() call. */
  52.  
  53. static int pass_to_stdio = 0;
  54.  
  55. void
  56. wsetstdio(flag)
  57.     int flag;
  58. {
  59.     pass_to_stdio = flag;
  60. }
  61. #endif
  62.  
  63. static EVENT pushback= {WE_NULL};
  64.  
  65. void
  66. wungetevent(ep)
  67.     EVENT *ep;
  68. {
  69.     pushback= *ep;
  70. }
  71.  
  72. static void
  73. wwaitevent(ep, wait)
  74.     EVENT *ep;
  75.     bool wait;
  76. {
  77.     _wfreeclip();
  78.     if (pushback.type != WE_NULL) {
  79.         *ep= pushback;
  80.         pushback.type= WE_NULL;
  81.         return;
  82.     }
  83.     
  84.     if (_wmenuhilite) {
  85.         HiliteMenu(0);
  86.         _wmenuhilite= FALSE;
  87.     }
  88.     
  89.     if (active == NULL)
  90.         set_arrow();
  91.     else if (active->w != FrontWindow()) {
  92.         /* Somehow we missed a deactivation event.
  93.            Fake one now. */
  94.         ep->type= WE_DEACTIVATE;
  95.         ep->window= active;
  96.         deactivate();
  97.         return;
  98.     }
  99.     
  100.     ep->type= WE_NULL;
  101.     ep->window= NULL;
  102.     
  103.     do {
  104.         if (!GetNextEvent(everyEvent, &e)) {
  105.             if (e.what == nullEvent) {
  106.                 if (wait) do_idle(ep);
  107.                 else return;
  108.             }
  109.         }
  110.         else {
  111. #ifndef NO_STDIO
  112.             /* Give THINK C stdio a chance to handle the event.
  113.                Unfortunately it also eats up clicks in
  114.                title bars, so, to save our Option-click feature,
  115.                we don't feed it those. */
  116.             if (pass_to_stdio &&
  117.                     !(e.what == mouseDown &&
  118.                       (e.modifiers & optionKey))) {
  119.                 if (StdEvent(&e))
  120.                     continue;
  121.             }
  122. #endif
  123.             switch (e.what) {
  124.             case mouseDown:
  125.                 do_mouse_down(ep);
  126.                 break;
  127.             case mouseUp:
  128.                 do_mouse_up(ep);
  129.                 break;
  130.             case keyDown:
  131.             case autoKey:
  132.                 do_key(ep);
  133.                 break;
  134.             case updateEvt:
  135.                 do_update(ep);
  136.                 break;
  137.             case diskEvt:
  138.                 do_disk(ep);
  139.                 break;
  140.             case activateEvt:
  141.                 do_activate(ep);
  142.                 break;
  143.             }
  144.         }
  145.     } while (ep->type == WE_NULL);
  146.     
  147.     if (ep->window == NULL)
  148.         ep->window= whichwin(FrontWindow());
  149.     if (!_wm_down)
  150.         set_watch();
  151. }
  152.  
  153. int
  154. wpollevent(ep)
  155.         EVENT *ep;
  156. {
  157.         ep->type = WE_NULL;
  158.         wwaitevent(ep, FALSE);
  159.         return ep->type != WE_NULL;
  160. }
  161.  
  162. void
  163. wgetevent(ep)
  164.         EVENT *ep;
  165. {
  166.         wwaitevent(ep, TRUE);
  167. }
  168.  
  169. static void
  170. do_idle(ep)
  171.     EVENT *ep;
  172. {    
  173.     if (checktimer(ep))
  174.         return;
  175.     
  176.     if (_w_idle_proc != NULL)
  177.         (*_w_idle_proc)();
  178.     
  179.     /* The user idle proc may have called wungetevent: */
  180.     if (pushback.type != WE_NULL) {
  181.         *ep= pushback;
  182.         pushback.type= WE_NULL;
  183.         return;
  184.     }
  185.     
  186.     SystemTask();
  187.     
  188.     if (active != NULL) {
  189.         Point where;
  190.         Rect r;
  191.         
  192.         where= e.where;
  193.         SetPort(active->w);
  194.         GlobalToLocal(&where);
  195.         if (_wm_down) {
  196.             autoscroll(active, where.h, where.v);
  197.             make_mouse_event(ep, &where);
  198.             return;
  199.         }
  200.         getwinrect(active, &r);
  201.         if (PtInRect(PASSPOINT where, &r)) {
  202.             if (e.modifiers & optionKey)
  203.                 set_hand();
  204.             else
  205.                 set_applcursor();
  206.         }
  207.         else
  208.             set_arrow();
  209.         blinkcaret(active);
  210.     }
  211. }
  212.  
  213. static void
  214. do_update(ep)
  215.     EVENT *ep;
  216. {
  217.     WINDOW *win;
  218.     Rect r;
  219.     
  220.     win= whichwin((WindowPtr) e.message);
  221.     if (win == NULL) {
  222.         /* Update event for a window not created by STDWIN
  223.            (not a Desk Accessory -- these are taken care of
  224.            by GetNextEvent or at some other secret place.)
  225.            This is is problem: if we ignore it, it will come
  226.            back forever, so we'll never be idle again. */
  227. #ifdef THINK_C
  228. #ifndef THINK_C_3_0
  229.         /* Most likely, under THINK C 4.0, it is the console
  230.            window.  We can force the window to repaint itself
  231.            by calling any console function.  A rather harmless
  232.            one is cgetxy.  Use stderr as the one least likely
  233.            to be redirected. */
  234.         int x, y;
  235.         if (stderr->window)
  236.             cgetxy(&x, &y, stderr);
  237. #endif
  238. #endif
  239.         return;
  240.     }
  241.     _wupdate(win, &r);
  242.     if (win->drawproc == NULL && !EmptyRect(&r)) {
  243.         ep->type= WE_DRAW;
  244.         ep->window= win;
  245.         ep->u.area.left= r.left;
  246.         ep->u.area.top= r.top;
  247.         ep->u.area.right= r.right;
  248.         ep->u.area.bottom= r.bottom;
  249.     }
  250. }
  251.  
  252. static void
  253. do_mouse_down(ep)
  254.     EVENT *ep;
  255. {
  256.     WindowPtr w;
  257.     int code= FindWindow(PASSPOINT e.where, &w);
  258.     
  259.     if (code != inContent && code != inSysWindow)
  260.         set_arrow();
  261.     switch (code) {
  262.     case inMenuBar:
  263.         _wdo_menu(ep, MenuSelect(PASSPOINT e.where));    
  264.         break;
  265.     case inSysWindow:
  266.         SystemClick(&e, w);
  267.         break;
  268.     case inContent:
  269.         do_click(ep, w);
  270.         break;
  271.     case inDrag:
  272.         do_drag(w);
  273.         break;
  274.     case inGrow:
  275.         do_grow(ep, w);
  276.         break;
  277.     case inGoAway:
  278.         do_goaway(ep, w);
  279.         break;
  280.     case inZoomIn:
  281.     case inZoomOut:
  282.         do_zoom(ep, w, code);
  283.         break;
  284.     }
  285. }
  286.  
  287. static void
  288. do_mouse_up(ep)
  289.     EVENT *ep;
  290. {
  291.     do_unclick(ep);
  292. }
  293.  
  294. static void
  295. do_key(ep)
  296.     EVENT *ep;
  297. {
  298.     int c= e.message & charCodeMask;
  299.     
  300.     if (e.modifiers & cmdKey) {
  301.         if (c == '.') {
  302.             ep->type= WE_COMMAND;
  303.             ep->u.command= WC_CANCEL;
  304.         }
  305.         else {
  306.             long menu_item= MenuKey(c);
  307.             if (HiWord(menu_item) != 0) {
  308.                 _wdo_menu(ep, menu_item);
  309.             }
  310.             else {
  311.                 ep->type= WE_KEY;
  312.                 ep->u.key.code= c;
  313.                 ep->u.key.mask= WM_META;
  314.                 /* Should filter out arrow keys? */
  315.             }
  316.         }
  317.     }
  318.     else {
  319.         ep->type= WE_COMMAND;
  320.         switch (c) {
  321.         
  322.         default:
  323.             ObscureCursor();
  324.             ep->type= WE_CHAR;
  325.             ep->u.character= c;
  326.             break;
  327.         
  328.         case LEFT_ARROW:
  329.         case RIGHT_ARROW:
  330.         case UP_ARROW:
  331.         case DOWN_ARROW:
  332.             ep->u.command= c-LEFT_ARROW + WC_LEFT;
  333.             break;
  334.         
  335.         case '\b':
  336.             ObscureCursor();
  337.             ep->u.command= WC_BACKSPACE;
  338.             break;
  339.         
  340.         case '\t':
  341.             ObscureCursor();
  342.             ep->u.command= WC_TAB;
  343.             break;
  344.         
  345.         case '\r':
  346.         case ENTER_KEY:
  347.             ep->u.command= WC_RETURN;
  348.             break;
  349.         
  350.         }
  351.     }
  352. }
  353.  
  354. static void
  355. do_disk(ep)
  356.     EVENT *ep;
  357. {
  358.     /* XXX Disk events not implemented -- who cares. */
  359. }
  360.  
  361. /* XXX Need to be easier for cases where we seem to have missed events */
  362.  
  363. static void
  364. do_activate(ep)
  365.     EVENT *ep;
  366. {
  367.     WINDOW *win= whichwin((WindowPtr)e.message);
  368.     
  369.     if (win == NULL) {
  370.         /* dprintf("(de)activate evt for alien window"); */
  371.         return;
  372.     }
  373.     
  374.     if (e.modifiers & activeFlag) { /* Activation */
  375.         if (active != NULL) {
  376.             /* Perhaps reactivation after modal dialog */
  377. #ifdef NO_STDIO
  378.             /* But perhaps THINK C stdio is fooling us */
  379.             if (active == win)
  380.                 return;
  381.             /* If we get here we've missed a
  382.                deactivate event... */
  383.             /* dprintf("activate without deactivate"); */
  384. #endif
  385.         }
  386.         activate(win);
  387.         ep->type= WE_ACTIVATE;
  388.         ep->window= active;
  389.     }
  390.     else { /* Deactivation */
  391.         if (win != active) {
  392.             /* Spurious deactivation event.
  393.                This always happens when we open
  394.                two or more windows without intervening
  395.                call to wgetevent().
  396.                Perhaps an conscious hack in the
  397.                ROM to "help" programs that believe
  398.                windows are created active? */
  399.             return;
  400.         }
  401.         ep->type= WE_DEACTIVATE;
  402.         ep->window= active;
  403.         deactivate();
  404.     }
  405. }
  406.  
  407. static void
  408. deactivate()
  409. {
  410.     SetPort(active->w);
  411.     rmcaret(active);
  412.     hidescrollbars(active);
  413.     rmlocalmenus(active);
  414.     _wgrowicon(active);
  415.     active= NULL;
  416.     set_arrow();
  417. }
  418.  
  419. static void
  420. activate(win)
  421.     WINDOW *win;
  422. {
  423.     if (active != NULL)
  424.         deactivate();
  425.     if (win != NULL) {
  426.         SetPort(win->w);
  427.         active= win;
  428.         showscrollbars(win);
  429.         addlocalmenus(active);
  430.         valid_border(win->w); /* Avoid flicker when window pops up */
  431.     }
  432. }
  433.  
  434. static void
  435. do_click(ep, w)
  436.     EVENT *ep;
  437.     WindowPtr w;
  438. {
  439.     WINDOW *win= whichwin(w);
  440.     Point where;
  441.     int pcode;
  442.     ControlHandle bar;
  443.     
  444.     if (win == NULL) {
  445.         /* dprintf("click in alien window"); */
  446.         return;
  447.     }
  448.     if (win != active) {
  449.         set_arrow();
  450.         if (e.modifiers & optionKey) {
  451.             /* Option-click sends a window behind. */
  452.             SendBehind(w, (WindowPtr) NULL);
  453.         }
  454.         else
  455.             SelectWindow(win->w);
  456.         return;
  457.         /* Let activate events do the rest. */
  458.     }
  459.     where= e.where;
  460.     SetPort(win->w);
  461.     GlobalToLocal(&where);
  462.     pcode= FindControl(PASSPOINT where, w, &bar);
  463.     if (pcode != 0) {
  464.         set_arrow();
  465.         do_scroll(&where, win, bar, pcode);
  466.     }
  467.     else {
  468.         Rect r;
  469.         
  470.         getwinrect(win, &r);
  471.         if (PtInRect(PASSPOINT where, &r)) {
  472.             if (e.modifiers & optionKey) {
  473.                 set_hand();
  474.                 dragscroll(win,
  475.                     where.h, where.v,
  476.                     e.modifiers & shiftKey);
  477.             }
  478.             else {
  479.                 set_applcursor();
  480.                 make_mouse_event(ep, &where);
  481.             }
  482.         }
  483.     }
  484. }
  485.  
  486. static void
  487. do_unclick(ep)
  488.     EVENT *ep;
  489. {
  490.     if (active != NULL) {
  491.         Point where;
  492.         
  493.         where= e.where;
  494.         SetPort(active->w);
  495.         GlobalToLocal(&where);
  496.         make_mouse_event(ep, &where);
  497.     }
  498. }
  499.  
  500. static void
  501. do_drag(w)
  502.     WindowPtr w;
  503. {
  504.     if (e.modifiers & optionKey) {
  505.         /* Nonstandard: option-click sends a window behind. */
  506.         SendBehind(w, (WindowPtr) NULL);
  507.     }
  508.     else {
  509.         Rect r;
  510.         
  511.         r= screen->portRect;
  512.         r.top += MENUBARHEIGHT;
  513.         InsetRect(&r, 4, 4);
  514.         DragWindow(w, PASSPOINT e.where, &r);
  515.     }
  516. }
  517.  
  518. static void
  519. do_grow(ep, w)
  520.     EVENT *ep;
  521.     WindowPtr w;
  522. {
  523.     Rect r;
  524.     long reply;
  525.     WINDOW *win = whichwin(w);
  526.     
  527.     /* Don't mess at all with non-stdwin windows */
  528.     if (win == NULL)
  529.         return;
  530.     
  531.     /* Set minimal window size --
  532.       1x1 at least, plus space needed for scroll bars */
  533.     r.left = LSLOP + 1 + RSLOP;
  534.     r.top = 1;
  535.     if (win->hbar != NULL)
  536.         r.left = 3*BAR;
  537.     if (win->vbar != NULL)
  538.         r.top = 3*BAR;
  539.     if (win->vbar != NULL)
  540.         r.left += BAR;
  541.     if (win->hbar != NULL)
  542.         r.top += BAR;
  543.     
  544.     /* Windows may become as large as the user can get them,
  545.        within reason -- the limit 0x7000 should avoid integer
  546.        overflow in QuickDraw. */
  547.     r.right = r.bottom = 0x7000;
  548.     
  549.     reply= GrowWindow(w, PASSPOINT e.where, &r);
  550.     if (reply != 0) {
  551.         SetPort(w);
  552.         inval_border(w);
  553.         SizeWindow(w, LoWord(reply), HiWord(reply), TRUE);
  554.         do_size(ep, w);
  555.     }
  556. }
  557.  
  558. static void
  559. do_goaway(ep, w)
  560.     EVENT *ep;
  561.     WindowPtr w;
  562. {
  563.     /* XXX shouldn't mess at all with non-stdwin windows */
  564.     
  565.     if (TrackGoAway(w, PASSPOINT e.where)) {
  566.         ep->type= WE_CLOSE;
  567.         ep->window= whichwin(w);
  568.     }
  569. }
  570.  
  571. static void
  572. do_zoom(ep, w, code)
  573.     EVENT *ep;
  574.     WindowPtr w;
  575.     int code;
  576. {
  577.     /* XXX shouldn't mess at all with non-stdwin windows */
  578.     
  579.     /* This code will never be reached on a machine
  580.        with old (64K) ROMs, because FindWindow will
  581.        never return inZoomIn or inZoomOut.
  582.        Therefore, no check for new ROMs is necessary.
  583.        A warning in Inside Macintosh IV says that
  584.        it is necessary to make the zoomed window
  585.        the current GrafPort before calling ZoomWindow.
  586.        True enough, it fails spectacularly otherwise,
  587.        but still this looks like a bug to me - there
  588.        are no similar requirements for SizeWindow
  589.        or DragWindow. */
  590.     
  591.     SetPort(w);
  592.     if (TrackBox(w, PASSPOINT e.where, code)) {
  593.         inval_border(w);
  594.         ZoomWindow(w, code, TRUE);
  595.         do_size(ep, w);
  596.     }
  597. }
  598.  
  599. /* do_size assumes w is already the current grafport */
  600.  
  601. static void
  602. do_size(ep, w)
  603.     EVENT *ep;
  604.     WindowPtr w;
  605. {
  606.     WINDOW *win= whichwin(w);
  607.     
  608.     if (win == NULL) {
  609.         /* dprintf("alien window resized"); */
  610.         return;
  611.     }
  612.     inval_border(w);
  613.     movescrollbars(win);
  614.     ep->type= WE_SIZE;
  615.     ep->window= win;
  616.     _wfixorigin(win);
  617. }
  618.  
  619. void
  620. inval_border(w)
  621.     WindowPtr w;
  622. {
  623.     Rect r;
  624.     WINDOW *win = whichwin(w);
  625.     
  626.     if (win->vbar != NULL) {
  627.         r = w->portRect;
  628.         r.left = r.right - BAR;
  629.         InvalRect(&r);
  630.     }
  631.     if (win->hbar != NULL) {
  632.         r = w->portRect;
  633.         r.top = r.bottom - BAR;
  634.         InvalRect(&r);
  635.     }
  636. }
  637.  
  638. void
  639. valid_border(w)
  640.     WindowPtr w;
  641. {
  642.     Rect r;
  643.     WINDOW *win = whichwin(w);
  644.     
  645.     if (win->vbar != NULL) {
  646.         r = w->portRect;
  647.         r.left = r.right - BAR;
  648.         ValidRect(&r);
  649.     }
  650.     if (win->hbar != NULL) {
  651.         r = w->portRect;
  652.         r.top = r.bottom - BAR;
  653.         ValidRect(&r);
  654.     }
  655. }
  656.  
  657. /* Variables needed in click and move detection. */
  658.  
  659. static int m_h, m_v;        /* Doc. coord. of last mouse evt. */
  660. static long m_when;        /* TickCount of last mouse evt. */
  661. static int m_clicks;        /* N-fold click stage */
  662.  
  663. static void
  664. make_mouse_event(ep, pwhere)
  665.     EVENT *ep;
  666.     Point *pwhere;        /* Mouse pos. in local coord. */
  667. {
  668.     WINDOW *win= active;
  669.     int h= pwhere->h + win->orgh;
  670.     int v= pwhere->v + win->orgv;
  671.     int dh= h - m_h;
  672.     int dv= v - m_v;
  673.     int mask;
  674.     
  675.     if (m_clicks != 0 && dh*dh + dv*dv > CLICK_DIST*CLICK_DIST)
  676.         m_clicks= 0;    /* Moved too much for a click */
  677.     
  678.     if (e.what == mouseDown) {
  679.         if (e.when > m_when + GetDblTime())
  680.             m_clicks= 1;
  681.         else
  682.             ++m_clicks;
  683.         ep->type= WE_MOUSE_DOWN;
  684.         _wm_down= TRUE;
  685.     }
  686.     else if (e.what == mouseUp) {
  687.         if (!_wm_down)
  688.             return;
  689.         ep->type= WE_MOUSE_UP;
  690.         _wm_down= FALSE;
  691.     }
  692.     else {
  693.         if (!_wm_down || m_clicks > 0 || (dh == 0 && dv == 0))
  694.             return;
  695.         ep->type= WE_MOUSE_MOVE;
  696.     }
  697.     mask= (ep->type == WE_MOUSE_UP) ? 0 : WM_BUTTON1;
  698.     if (e.modifiers & cmdKey)
  699.         mask |= WM_META;
  700.     if (e.modifiers & shiftKey)
  701.         mask |= WM_SHIFT;
  702.     if (e.modifiers & alphaLock)
  703.         mask |= WM_LOCK;
  704.     if (e.modifiers & optionKey)
  705.         mask |= WM_OPTION;
  706.     if (e.modifiers & controlKey)
  707.         mask |= WM_CONTROL;
  708.     ep->u.where.h= m_h= h;
  709.     ep->u.where.v= m_v= v;
  710.     ep->u.where.clicks= m_clicks;
  711.     ep->u.where.button= 1;
  712.     ep->u.where.mask= mask;
  713.     ep->window= win;
  714.     m_when= e.when;
  715. }
  716.  
  717. /* Reset the mouse state.
  718.    Called when a dialog is started. */
  719.  
  720. void
  721. _wresetmouse()
  722. {
  723.     _wm_down= FALSE;
  724. }
  725.  
  726. void
  727. wsetactive(win)
  728.     WINDOW *win;
  729. {
  730.     SelectWindow(win->w);
  731. }
  732.  
  733. WINDOW *
  734. wgetactive()
  735. {
  736.     return whichwin(FrontWindow());
  737. }
  738.